//============================================================================
// Name        : f_engine.cpp
// Author      : inkooboo
// Version     :
// Copyright   : 
// Description :
//============================================================================

#include "f_engine.hpp"

#include "misc/config.hpp"
#include "misc/errors.hpp"

#include "systems/render.hpp"
#include "systems/scheduler.hpp"
#include "systems/res_manager.hpp"
#include "systems/logger.hpp"
#include "systems/scripting.hpp"
#include "systems/object_manager.hpp"
#include "systems/physics.hpp"
#include "systems/events_sender.hpp"
#include "systems/events_dispatcher.hpp"

#include <boost/foreach.hpp>

#include <string>

using namespace std;

f_engine_t::f_engine_t() :
    config_("config.xml")
{

    add_system<res_manager_t> ();
    add_system<object_manager_t> ();
    add_system<scheduler_t> ();
    add_system<render_t> ();
    add_system<physics_manager_t> ();
    add_system<events_sender_t> ();
    add_system<events_dispatcher_t> ();

    system_started_barrier_.reset(new barrier_t(systems_creation_order_.size()));
}

f_engine_t::~f_engine_t()
{
    logger::log(DEBUG, "Destroying f_engine...");
   //delete all systems in reverse order
    systems_creation_order_t::reverse_iterator r_it = systems_creation_order_.rbegin();
    while (r_it != systems_creation_order_.rend())
    {
        logger::log(DEBUG) << "Destroying system " << typeid(*(*r_it).get()).name();
        (*r_it).reset();
        ++r_it;
    }
}

void f_engine_t::report_started()
{
    system_started_barrier_->release_one();
}

void f_engine_t::wait_all_systems()
{
    system_started_barrier_->wait();
}

void f_engine_t::start()
{

    //load resource locations
    BOOST_FOREACH(const config_t::opt_t::value_type &param, config_.tree.get_child("Engine.Resources"))
                {
                    system<res_manager_t> ().add_res_location(param.second.data());
                }

    //start all systems
    BOOST_FOREACH(systems_creation_order_t::value_type &i, systems_creation_order_)
                {
                    i->start();
                }

    //wait until all systems will be started
    wait_all_systems();

    //run script
    boost::shared_ptr<scripting_instance_t> script = scripting_instance_t::create(this, "level.lua");

    script->register_common();
    script->register_object_api();

    script->run_script();
}
